package com.example.dbsample.util.date;

import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;

//import javax.annotation.Nullable;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author yuzhou
 * @date 2017/6/16
 * @time 11:22:27
 */
@Slf4j
public class DateTimeUtils {

    private DateTimeUtils() {

    }

    private static final Map<String, DateTimeFormatter> formatterMap = new ConcurrentHashMap<>();

    public static final String PATTERN_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static final String PATTERN_YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";

    public static final String PATTERN_YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";


    public static final String PATTERN_YYYYMMDD = "yyyyMMdd";
    public static final String PATTERN_YYYYMMDDHHMMSSSSS = "yyyyMMddHHmmssSSS";
    public static final String PATTERN_YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static final String PATTERN_YYYY_MM_DD = "yyyy-MM-dd";
    public static final String PATTERN_HH_MM_SS = "HH:mm:ss";
    public static final String PATTERN_HH_MM = "HH:mm";

    public static final String PATTERN_ZERO = "00:00:00";

    public static final Long DAY_M = 24 * 60 * 60 * 1000L;

    public static final DateTimeFormatter DEFAULT_DATEMILLTIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
    public static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    public static final DateTimeFormatter DEFAULT_SHORT_DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyMMddHHmmss");
    public static final DateTimeFormatter DEFAULT_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    public static final DateTimeFormatter DEFAULT_SHORT_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyMMdd");
    public static final DateTimeFormatter DEFAULT_MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM");
    public static final DateTimeFormatter DEFAULT_TIME_FORMATTER = DateTimeFormatter.ofPattern("HHmmss");
    public static final DateTimeFormatter DEFAULT_DAY_FORMATTER = DateTimeFormatter.ofPattern("dd");

    private static final ThreadLocal<DateFormat> threadLocalDateFormat = new ThreadLocal();

    private static String localFormat = null;

    private static final Map<String, org.joda.time.format.DateTimeFormatter> jodaFormatterMap = Maps.newHashMap();

    private static final SimpleDateFormat format = new SimpleDateFormat(PATTERN_YYYY_MM_DD);

    private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(PATTERN_YYYY_MM_DD_HH_MM_SS).withZone(ZoneId.of("GMT+8"));
    /**
     * Returns the current date
     *
     */
    public static LocalDate getCurrentLocalDate() {
        return LocalDate.now();
    }

    /**
     * Returns the current time
     *
     */
    public static LocalTime getCurrentLocalTime() {
        return LocalTime.now();
    }

    /**
     * Returns the current date time
     *
     */
    public static LocalDateTime getCurrentLocalDateTime() {
        return LocalDateTime.now();
    }

    /**
     * yyyyMMdd
     *
     */
    public static String getCurrentDateStr() {
        return LocalDate.now().format(DEFAULT_DATE_FORMATTER);
    }

    /**
     * dd
     *
     */
    public static String getCurrentDayStr() {
        return LocalDate.now().format(DEFAULT_DAY_FORMATTER);
    }

    /**
     * yyMMdd
     *
     * @return
     */
    public static String getCurrentShortDateStr() {
        return LocalDate.now().format(DEFAULT_SHORT_DATE_FORMATTER);
    }

    public static String getCurrentMonthStr() {
        return LocalDate.now().format(DEFAULT_MONTH_FORMATTER);
    }

    /**
     * yyyyMMddHHmmss
     *
     * @return
     */
    public static String getCurrentDateTimeStr() {
        return LocalDateTime.now().format(DEFAULT_DATETIME_FORMATTER);
    }

    /**
     * yyMMddHHmmss
     *
     * @return
     */
    public static String getCurrentShortDateTimeStr() {
        return LocalDateTime.now().format(DEFAULT_SHORT_DATETIME_FORMATTER);
    }

    /**
     * HHmmss
     *
     */
    public static String getCurrentTimeStr() {
        return LocalTime.now().format(DEFAULT_TIME_FORMATTER);
    }

    public static String getCurrentDateStr(String pattern) {
        return LocalDate.now().format(DateTimeFormatter.ofPattern(pattern));
    }

    public static String getCurrentDateTimeStr(String pattern) {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(pattern));
    }

    public static String getCurrentTimeStr(String pattern) {
        return LocalTime.now().format(DateTimeFormatter.ofPattern(pattern));
    }

    public static LocalDate parseLocalDate(String dateStr, String pattern) {
        return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
    }

    public static LocalDateTime parseLocalDateTime(String dateTimeStr, String pattern) {
        return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern(pattern));
    }

    public static LocalTime parseLocalTime(String timeStr, String pattern) {
        return LocalTime.parse(timeStr, DateTimeFormatter.ofPattern(pattern));
    }

    public static String formatLocalDate(LocalDate date, String pattern) {
        return date.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static String formatLocalDateTime(LocalDateTime datetime, String pattern) {
        return datetime.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static String formatLocalTime(LocalTime time, String pattern) {
        return time.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static LocalDate parseLocalDate(String dateStr) {
        return LocalDate.parse(dateStr, DEFAULT_DATE_FORMATTER);
    }

    public static LocalDateTime parseLocalDateTime(String dateTimeStr) {
        return LocalDateTime.parse(dateTimeStr, DEFAULT_DATETIME_FORMATTER);
    }

    public static LocalTime parseLocalTime(String timeStr) {
        return LocalTime.parse(timeStr, DEFAULT_TIME_FORMATTER);
    }

    public static String formatLocalDate(LocalDate date) {
        return date.format(DEFAULT_DATE_FORMATTER);
    }

    public static String formatLocalDateTime(LocalDateTime datetime) {
        return datetime.format(DEFAULT_DATETIME_FORMATTER);
    }

    public static String formatLocalDateMillsTime(LocalDateTime datetime) {
        return datetime.format(DEFAULT_DATEMILLTIME_FORMATTER);
    }

    public static String formatLocalTime(LocalTime time) {
        return time.format(DEFAULT_TIME_FORMATTER);
    }

    /**
     * Days apart
     *
     * @param startDateInclusive
     * @param endDateExclusive
     * @return
     */
    public static int periodDays(LocalDate startDateInclusive, LocalDate endDateExclusive) {
        return Period.between(startDateInclusive, endDateExclusive).getDays();
    }

    /**
     * Hours apart
     *
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long durationHours(Temporal startInclusive, Temporal endExclusive) {
        return Duration.between(startInclusive, endExclusive).toHours();
    }

    /**
     * Minutes apart
     *
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long durationMinutes(Temporal startInclusive, Temporal endExclusive) {
        return Duration.between(startInclusive, endExclusive).toMinutes();
    }

    /**
     * The number of milliseconds between the dates
     *
     * @param startInclusive
     * @param endExclusive
     * @return
     */
    public static long durationMillis(Temporal startInclusive, Temporal endExclusive) {
        return Duration.between(startInclusive, endExclusive).toMillis();
    }

    /**
     * Whether in the day
     *
     * @param date
     * @return
     */
    public static boolean isToday(LocalDate date) {
        return getCurrentLocalDate().equals(date);
    }

    public static Long toEpochMilli(LocalDateTime dateTime) {
        return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    public static Date getRegistrationTime(String registrationTime) throws ParseException {
        return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(registrationTime);
    }


    public static LocalDateTime getLocalDateTimeBeforeDays(int days) {
		return LocalDateTime.now().plusDays(-days);
	}

	public static Date getDateBeforeDays(int days) {
		return DateUtils.addDays(new Date(), -days);
	}

	public static Date getBeginOfDate(String timeStr) throws ParseException {
		return DateUtils.parseDate(timeStr, "yyyy-MM-dd");
    }


    public static Date getBeginOfDate(Date date) {
        if(date == null) {
            date = new Date();
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }

	public static Date getEndOfDate(String timeStr) throws ParseException {
		Date parseDate = DateUtils.parseDate(timeStr, "yyyy-MM-dd");
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(parseDate);
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		return calendar.getTime();
	}

    public static Date getEndOfDate(Date date) {
        if(date == null) {
            date = new Date();
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }

	public static LocalDate dateToLocalDate(Date date) {
		Instant instant = date.toInstant();
	    ZoneId zone = ZoneId.systemDefault();
	    LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
	    return localDateTime.toLocalDate();
	}


	/**
	 * get days between two date
	 * @param begin
	 * @param end
	 * @return
	 */
	public static Integer getDaysBetweenTwoDate(Date begin, Date end) {
		begin = null != begin ? begin : new Date();
		end = null != end ? end : new Date();
		LocalDate beginLocalDate = dateToLocalDate(begin);
		LocalDate endLocalDate = dateToLocalDate(end);
		Period pe = Period.between(beginLocalDate, endLocalDate);
		return pe.getDays();
	}


	/**
	 * get years betwwen date
	 * @param begin
	 * @param end
	 * @return
	 */
	public static Integer getYearsBetweenTwoDate(Date begin, Date end) {
		begin = null != begin ? begin : new Date();
		end = null != end ? end : new Date();
		LocalDate LocalDate1 = dateToLocalDate(begin);
		LocalDate LocalDate2 = dateToLocalDate(end);
		return Period.between(LocalDate1, LocalDate2).getYears();
	}
	
	public static String getYYYYMMDDString() {
		return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
	}

	public static Date getAfterMonth(int month) {
		return DateUtils.addMonths(new Date(), month);
	}

    public static DateTimeFormatter getFormat() {
        return dateTimeFormatter;
    }

    public static org.joda.time.format.DateTimeFormatter getJodaFormat() {
        return getJodaFormat(PATTERN_YYYY_MM_DD_HH_MM_SS_SSS);
    }

    public static org.joda.time.format.DateTimeFormatter getJodaFormat(String format) {
        return jodaFormatterMap.computeIfAbsent(format, org.joda.time.format.DateTimeFormat::forPattern);
    }
  

    /**
     * 按yyyy-MM-dd HH:mm: ss格式获取当前时间
     */
    public static String formatNow() {
        return format(PATTERN_YYYY_MM_DD_HH_MM_SS, LocalDateTime.now());
    }

    /**
     * 按yyyy-MM-dd HH:mm:ss.SSS格式获取当前时间戳
     */
    public static String formatNowWithMillis() {
        return format(PATTERN_YYYY_MM_DD_HH_MM_SS_SSS, LocalDateTime.now());
    }

    /**
     * 获取当前时间戳
     */
    public static String formatNow(String pattern) {
        return format(pattern, LocalDateTime.now());
    }

    /**
     * 时间格式化
     */
    public static String format(String pattern, LocalDateTime dateTime) {
        if(dateTime != null) {
            DateTimeFormatter formatter = formatterMap.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
            return dateTime.format(formatter);
        }
        return "";
    }

    /**
     * 时间戳字符串转LocalDateTime对象
     */
    public static LocalDateTime parse(String pattern, String dateTimeString) {
        DateTimeFormatter formatter = formatterMap.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
        return LocalDateTime.parse(dateTimeString, formatter);
    }

    /**
     * 时间戳字符串转LocalDateTime对象
     * 并使用yyyy-MM-dd HH:mm:ss
     * @param pattern
     * @param dateTimeString
     * @return
     */
    public static LocalDateTime parseDefault(String pattern, String dateTimeString) {
        DateTimeFormatter formatter = formatterMap.computeIfAbsent(DateTimeUtils.PATTERN_YYYY_MM_DD_HH_MM_SS, DateTimeFormatter::ofPattern);
        return LocalDateTime.parse(dateTimeString, formatter);
    }

    /**
     * 格式 例子：yyyy-MM-dd HH:mm:ss.SSS
     */
    public static String timeToString(String pattern, Long time) {
        DateTimeFormatter formatter = formatterMap.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
        return formatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()));
    }

    public static Long getDurationByTimeUnitV2(String pattern,
                                                String endDateTimeStr,
                                                String startDateTimeStr,
                                               TimeUnit timeUnit) {
        LocalDateTime endDateTime = parse(pattern, endDateTimeStr);

        LocalDateTime startDateTime = parse(pattern, startDateTimeStr);

        return getDurationByTimeUnitV2(endDateTime, startDateTime, timeUnit);
    }
    /**
     * 按时间单位输出时间段差值
     */
    public static Long getDurationByTimeUnitV2(LocalDateTime endDateTime,
                                             LocalDateTime startDateTime,
                                             TimeUnit timeUnit) {
        Duration duration = Duration.between(startDateTime, endDateTime);
        if(TimeUnit.DAYS.equals(timeUnit)) {
            return duration.toDays();
        } else if(TimeUnit.HOURS.equals(timeUnit)) {
            return duration.toHours();
        } else if(TimeUnit.MINUTES.equals(timeUnit)) {
            return duration.toMinutes();
        } else if(TimeUnit.SECONDS.equals(timeUnit)) {
            return duration.getSeconds();
        } else if(TimeUnit.MILLISECONDS.equals(timeUnit)) {
            return duration.toMillis();
        } else if(TimeUnit.MICROSECONDS.equals(timeUnit)) {
            return duration.toNanos() / 1000;
        } else if(TimeUnit.NANOSECONDS.equals(timeUnit)) {
            return duration.toNanos();
        } else {
            throw new UnsupportedOperationException();
        }
    }

    /**
     * 按时间单位输出时间段差值 - V2
     */
    public static Long getDurationByTimeUnitV3(String pattern,
                                               String endDateTimeString,
                                               String startDateTimeString,
                                               TimeUnit timeUnit) {


        if(StringUtils.isEmpty(startDateTimeString) || StringUtils.isEmpty(endDateTimeString)) {
            return 0L;
        }

        if(pattern.equals(DateTimeUtils.PATTERN_YYYY_MM_DD_HH_MM_SS)) {
            startDateTimeString = startDateTimeString.split("\\.")[0];
        }
        if(pattern.equals(DateTimeUtils.PATTERN_YYYY_MM_DD_HH_MM_SS)) {
            endDateTimeString = endDateTimeString.split("\\.")[0];
        }
        if(pattern.equals(DateTimeUtils.PATTERN_YYYY_MM_DD_HH_MM_SS_SSS)) {
            if(!endDateTimeString.contains(".")) {
                endDateTimeString = endDateTimeString + ".000";
            }
            if(!startDateTimeString.contains(".")) {
                startDateTimeString = startDateTimeString + ".000";
            }
        }
        LocalDateTime startDateTime = parse(pattern, startDateTimeString);
        LocalDateTime endDateTime = parse(pattern, endDateTimeString);
        Duration duration = Duration.between(endDateTime, startDateTime);
        return dealTimeV2(timeUnit, duration, Math.abs(duration.getSeconds()));
    }

    public static Long getDurationByTimeUnitV5(
            String pattern,
            String startDateTimeStr,
            String endDateTimeStr,
            TimeUnit timeUnit) {
        LocalDateTime startDateTime = parse(pattern, startDateTimeStr);
        LocalDateTime endDateTime = parse(pattern, endDateTimeStr);
        return getDurationByTimeUnit(startDateTime, endDateTime, timeUnit);
    }

    /**
     * 将时间字符串转成时间戳
     */
    public static long getTmpFromStr(String dateStr, String pattern) {
        long date = 0L;
        if(StringUtils.isBlank(pattern)) {
            pattern = DateTimeUtils.PATTERN_YYYY_MM_DD_HH_MM_SS;
        }
        try {
            date = DateUtils.parseDate(dateStr, pattern). getTime();
        } catch(ParseException pe) {
            log.error("getTmpFromStr time parse error:", pe);
        } catch (Exception e) {
            log.error("getTmpFromStr time error:", e);
        }
        return date;
    }

    /**
     * 获取当前月第一天
     * @return
     */
    public static String currentFirstDay() {
        Calendar ld = Calendar.getInstance();
        ld.add(Calendar.MONTH, 0);
        ld.set(Calendar.DAY_OF_MONTH, 1);   // 设置为1号，当前日期即为本月第一天
        String firstDay = format.format(ld.getTime()) + " 00:00:00";
        return firstDay;
    }

    /**
     * 获取当前月最后一天
     * @return
     */
    public static String currentLastDay() {
        Calendar ld = Calendar.getInstance();
        ld.set(Calendar.DAY_OF_MONTH, ld.getActualMaximum(Calendar.DAY_OF_MONTH));
        String lastDay = format.format(ld.getTime()) + " 23.59:59";
        return lastDay;
    }

    public static Date parseToDate(String strDate, String format) throws ParseException {
        return getDateFormat(format).parse(strDate);
    }


    public static DateFormat getDateFormat(String format) {
        DateFormat dateFormat = threadLocalDateFormat.get();
        if(dateFormat == null || !format.equals(localFormat)) {
            dateFormat = new SimpleDateFormat(format);
            threadLocalDateFormat.set(dateFormat);
        }

        localFormat = format;
        return dateFormat;

    }

    public static Date parse2Date(String dateStr, String pattern) {
        DateTimeFormatter formatter = formatterMap.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
        return Date.from(LocalDateTime.parse(dateStr, formatter).atZone(ZoneId.systemDefault()).toInstant());
    }

    public static LocalDateTime getDateStart(LocalDateTime dateTime) {
        return dateTime.with(LocalTime.MIN);
    }

    public static LocalDateTime getDateEnd(LocalDateTime dateTime) {
        return dateTime.with(LocalTime.MAX);
    }

    private static long dealTimeV1(TimeUnit timeUnit, Duration duration) {
        if (TimeUnit.MILLISECONDS.equals(timeUnit)) {
            return duration.toMillis();
        } else if (TimeUnit.SECONDS.equals(timeUnit)) {
            return duration.getSeconds();
        } else if (TimeUnit.MINUTES.equals(timeUnit)) {
            return duration.toMinutes();
        } else if (TimeUnit.HOURS.equals(timeUnit)) {
            return duration.toHours();
        } else if (TimeUnit.DAYS.equals(timeUnit)) {
            return duration.toDays();
        } else if (TimeUnit.MICROSECONDS.equals(timeUnit)) {
            return duration.toNanos() / 1000;
        } else if (TimeUnit.NANOSECONDS.equals(timeUnit)) {
            return duration.toNanos();
        } else {
            throw new UnsupportedOperationException();
        }
    }
    private static long dealTimeV2(TimeUnit timeUnit, Duration duration, long duration1) {
         if (TimeUnit.MILLISECONDS.equals(timeUnit)) {
             return duration.toMillis();
         } else if (TimeUnit.SECONDS.equals(timeUnit)) {
             return duration1;
         } else if (TimeUnit.MINUTES.equals(timeUnit)) {
            return duration.toMinutes();
         } else if (TimeUnit.HOURS.equals(timeUnit)) {
             return duration.toHours();
         } else if (TimeUnit.DAYS.equals(timeUnit)) {
             return duration.toDays();
         } else if (TimeUnit.MICROSECONDS.equals(timeUnit)) {
             return duration.toNanos() / 1000;
         } else if (TimeUnit.NANOSECONDS.equals(timeUnit)) {
             return duration.toNanos();
         } else {
             throw new UnsupportedOperationException();
         }
    }

    /**
     * 按时间单位输出时间段差值
     * @param startDateTime
     * @param endDateTime
     * @param timeUnit
     * @return
     */
    public static Long getDurationByTimeUnit(LocalDateTime startDateTime,
                                              LocalDateTime endDateTime,
                                              TimeUnit timeUnit) {
        Duration duration = Duration.between(endDateTime, startDateTime);
        return dealTimeV2(timeUnit, duration, duration.getSeconds());
     }

    // public static Long stringToLong(String pattern, String time) {
    //     if(StringUtils.isEmpty(time)) {
    //         return 0L;
    //     }
    //     if(pattern.equals(PATTERN_YYYY_MM_DD_HH_MM_SS_SSS) && !time.contains(".")) {
    //         pattern = PATTERN_YYYY_MM_DD_HH_MM_SS;
    //     }
    //     SimpleDateFormat sdf = new SimpleDateFormat(pattern);
    //     try {
    //         return sdf.parse(time).getTime();
    //     } catch (ParseException e) {
    //         log.error("", e);
    //         return System.currentTimeMillis();
    //     }
    //}

    /**
     * pattern 格式 例子：yyyy-MM-dd HH:mm:ss.SSS
     * @param pattern
     * @param time
     * @return
     */
    public static Long stringToLong(String pattern, String time) {
        if(StringUtils.isEmpty(time)) {
            return 0L;
        }
        if(pattern.equals(PATTERN_YYYY_MM_DD_HH_MM_SS_SSS) && !time.contains(".")) {
            pattern = PATTERN_YYYY_MM_DD_HH_MM_SS;
        }

        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        try {
            return sdf.parse(time).getTime();
        } catch (ParseException e) {
            log.error("", e);
            return System.currentTimeMillis();
        }
    }

    public static String getBetweenT(String inPattern, String startDateTime,
                                     String endDateTime,
                                     String outPattern) {
        try {
            if(inPattern.equals(PATTERN_YYYY_MM_DD_HH_MM_SS_SSS) && (!startDateTime.contains(".") || !endDateTime.contains("."))) {
                inPattern = PATTERN_YYYY_MM_DD_HH_MM_SS;
            }
            if(inPattern.equals(PATTERN_YYYY_MM_DD_HH_MM_SS_SSS)) {
                if(startDateTime.contains(".") || endDateTime.contains(".")) {
                    startDateTime = startDateTime.split("\\.")[0];
                    endDateTime = endDateTime.split("\\.")[0];
                }
            }
            Long bT = checkParam(inPattern, startDateTime, endDateTime);
            if(bT == null) {
                return PATTERN_ZERO;
            }
            SimpleDateFormat sdf = new SimpleDateFormat(PATTERN_YYYY_MM_DD_HH_MM);
            String yyMMdd = sdf.format(new Date()).split(" ")[0];
            long realT = new SimpleDateFormat(PATTERN_YYYY_MM_DD_HH_MM).parse(yyMMdd + " " + PATTERN_ZERO).getTime() + bT;
            return new SimpleDateFormat(outPattern).format(new Date(realT));
        } catch (Exception e) {
            log.error("时间处理失败 inPattern: {}, startDateTime: {}, endDateTime: {}, outPattern: {}, ex: ",
                    inPattern, startDateTime, endDateTime, outPattern, e);
            return PATTERN_ZERO;
        }
    }

    // TODO 暂时去除
    //@Nullable
    private static Long checkParam(String inPattern, String startDateTime, String endDateTime) throws ParseException {
        if(StringUtils.isEmpty(endDateTime) || StringUtils.isEmpty(startDateTime)) {
            log.error("时间转换，参数异常，startDateTime: {}, endDateTime: {}", startDateTime, endDateTime);
            return null;
        }
        if(startDateTime.equals(endDateTime)) {
            return null;
        }
        SimpleDateFormat sdf1 = new SimpleDateFormat(inPattern);
        long bT = sdf1.parse(endDateTime).getTime() - sdf1.parse(startDateTime).getTime();
        if(bT < 1) {
            return null;
        }
        return bT;
    }

    /**
     * 按时间单位输出时间段差值
     */
     public static Long getDurationByTimeUnitV1(LocalDateTime endDateTime,
                                              LocalDateTime startDateTime,
                                              TimeUnit timeUnit) {
         Duration duration = Duration.between(startDateTime, endDateTime);
         if (TimeUnit.MILLISECONDS.equals(timeUnit)) {
             return duration.toMillis();
         } else if (TimeUnit.SECONDS.equals(timeUnit)) {
             return duration.getSeconds();
         } else if (TimeUnit.MINUTES.equals(timeUnit)) {
            return duration.toMinutes();
         } else if (TimeUnit.HOURS.equals(timeUnit)) {
             return duration.toHours();
         } else if (TimeUnit.DAYS.equals(timeUnit)) {
             return duration.toDays();
         } else if (TimeUnit.MICROSECONDS.equals(timeUnit)) {
             return duration.toNanos() / 1000;
         } else if (TimeUnit.NANOSECONDS.equals(timeUnit)) {
             return duration.toNanos();
         } else {
             throw new UnsupportedOperationException();
         }
     }


    /**
     * 判断当前时间是否在某个时间段内[06:00,22:00]
     * @param limit
     * @param phone
     * @return
     */
    public static Boolean isBelong(String begin, String end) {
        // 设置日期格式
        SimpleDateFormat df = new SimpleDateFormat("HH:mm");
        Date now = null;
        Date beginTime = null;
        Date endTime = null;
        try {
            now = df.parse(df.format(new Date()));
            beginTime = df.parse(begin);
            endTime = df.parse(end);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return belongCalendar(now, beginTime, endTime);
    }

    /**
     * 判断时间是否在时间段内
     * @param limit
     * @param phone
     * @return
     */
    public static boolean belongCalendar(Date nowTime, Date beginTime, Date endTime) {
        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);

        Calendar begin = Calendar.getInstance();
        begin.setTime(beginTime);

        Calendar end = Calendar.getInstance();
        begin.setTime(endTime);

        return date.compareTo(begin) >= 0 && date.before(end);
    }

    public static Date offsetHours(Date time, int offset) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.add(Calendar.HOUR, offset);
        return calendar.getTime();
    }

    public static Date offsetDay(Date time, int offset) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.add(Calendar.DATE, offset);
        return calendar.getTime();
    }

    public static Date offsetMonth(Date time, int offset) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.add(Calendar.MONTH, offset);
        return calendar.getTime();
    }

    public static void main(String[] args) {
        System.out.println(getYYYYMMDDString());
        System.out.printf("offsetMonth：%s%n", DateTimeUtils.offsetMonth(new Date(), -3));
    }

    /**
     * 获取当天0点的时间戳
     */
    public static LocalDateTime currentDayTime() {
        LocalDate today = LocalDate.now();
        LocalTime midnight = LocalTime.MIDNIGHT;
        LocalDateTime todayMidNight = LocalDateTime.of(today, midnight);
        return todayMidNight;
    }
}
